package com.css.fxfzdzzh.modules.basicData.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.PageUtil;
import com.css.fxfzdzzh.base.annotation.EntityValue;
import com.css.fxfzdzzh.base.exception.ShpFieldException;
import com.css.fxfzdzzh.base.response.RestResponse;
import com.css.fxfzdzzh.constants.FxfzConstants;
import com.css.fxfzdzzh.constants.GeomTypeEnum;
import com.css.fxfzdzzh.constants.YNEnum;
import com.css.fxfzdzzh.modules.basicData.entity.NaturalDensity;
import com.css.fxfzdzzh.modules.basicData.entity.SeismotectionBelt;
import com.css.fxfzdzzh.modules.basicData.entity.SeismotectionZone;
import com.css.fxfzdzzh.modules.basicData.landslideSite.entity.FieldDesc;
import com.css.fxfzdzzh.modules.basicData.landslideSite.vo.TableVo;
import com.css.fxfzdzzh.modules.basicData.repository.impl.SeismotectionRepository;
import com.css.fxfzdzzh.modules.basicData.vo.ListVo;
import com.css.fxfzdzzh.modules.basicData.vo.QueryByVersionParam;
import com.css.fxfzdzzh.util.PlatformDateUtils;
import com.css.fxfzdzzh.util.UUIDGenerator;
import com.css.fxfzdzzh.util.fileParsing.ParsingResult;
import com.css.fxfzdzzh.util.fileParsing.shp.ShpAnalyticUtil;
import com.css.fxfzdzzh.web.PlatformSessionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Dbj
 * @date 2023年04月25日  11:28
 */
@Slf4j
@Service
public class SeismotectionService {

    @Resource
    SeismotectionRepository seismotectionRepository;
    public void updateBeltByVersion(String tempVersionCode, String versionCode) {
        seismotectionRepository.updateBeltByVersion(tempVersionCode,versionCode,"dzzh_sys_seismotection_belt");
    }
    public void updateZoneByVersion(String tempVersionCode, String versionCode) {
        seismotectionRepository.updateBeltByVersion(tempVersionCode,versionCode,"dzzh_sys_seismotection_zone");
    }

    public void deleteBeltByVersion(String versionCode) {
        seismotectionRepository.deleteBeltByVersion(versionCode);
    }

    public RestResponse saveShpTemporaryData(ParsingResult shpData,String typeCode) {
        //生成临时版本号
        try {
            String dataVersion = UUID.randomUUID().toString().replaceAll("-", "");
            ListVo listVo = null;
            if(typeCode.equals(FxfzConstants.BELT)){
                List<SeismotectionBelt> list = this.getBeltList(shpData.getShpList(), dataVersion);
                if (list.size()>0){
                    seismotectionRepository.byBeltShpBatchSave(list);
                }
                listVo = new ListVo("0", null, dataVersion, "地震构造", null, list);
            }else if(typeCode.equals(FxfzConstants.ZONE)){
                List<SeismotectionZone> list = this.getZoneList(shpData.getShpList(), dataVersion);
                if (list.size()>0){
                    seismotectionRepository.byZoneShpBatchSave(list);
                }
                listVo = new ListVo("0", null, dataVersion, "地震构造", null, list);
            }
            return RestResponse.succeed(listVo);
        } catch (ShpFieldException e) {
            log.error(e.getMessage() + "\n错误数据 > {}", shpData.getShpList());
            return RestResponse.fail(e.getMessage());
        } catch (IndexOutOfBoundsException e1) {
            return RestResponse.fail("字段数量不符合要求");
        }
    }

    private List<SeismotectionZone> getZoneList(List<List<Object>> shpList, String dataVersion) throws ShpFieldException{
        ArrayList<SeismotectionZone> arrayList = new ArrayList<>();
        for (int i = 0; i < shpList.size(); i++) {
            List<Object> list = shpList.get(i);
            SeismotectionZone obj = new SeismotectionZone();
            //临时版本号
            obj.setDataVersion(dataVersion);
            //当前用户
            obj.setGeom(ShpAnalyticUtil.checkGeomTypeOf(list.get(0).toString(), GeomTypeEnum.MULTIPOLYGON));
            obj.setZoneName(ShpAnalyticUtil.getStringVal(list.get(1).toString(), "地震构造区名称", true));
            obj.setZoneNum(ShpAnalyticUtil.getStringVal(list.get(2).toString(), "地震构造区编号", true));
            obj.setBackgroundEarthquake(BigDecimal.valueOf(ShpAnalyticUtil.getDoubleVal(list.get(3).toString(), "背景地震", true)));
            obj.setBelongingZone(ShpAnalyticUtil.getStringVal(list.get(4).toString(), "所属地震带", true));
            obj.setMaxEarthQuake(BigDecimal.valueOf(ShpAnalyticUtil.getDoubleVal(list.get(5).toString(), "最大潜在地震", true)));
            obj.setZoneContent(ShpAnalyticUtil.getStringVal(list.get(6).toString(), "地震构造区内容", true));
            obj.setCreateUser(PlatformSessionContext.getUserID());
            obj.setCreateTime(new Date());
            obj.setDelFlag(YNEnum.N.toString());
            obj.setZoneId(UUIDGenerator.getUUID());
            arrayList.add(obj);
        }
        return arrayList;
    }

    private List<SeismotectionBelt> getBeltList(List<List<Object>> shpList, String dataVersion) throws ShpFieldException{
        ArrayList<SeismotectionBelt> arrayList = new ArrayList<>();
        for (int i = 0; i < shpList.size(); i++) {
            List<Object> list = shpList.get(i);
            SeismotectionBelt obj = new SeismotectionBelt();
            //临时版本号
            obj.setDataVersion(dataVersion);
            if("".equals(list.get(0))|| list.get(0)==null){
                throw new ShpFieldException("区带编号"+list.get(4).toString()+"的空间数据有误");
            }else{
                obj.setGeom(ShpAnalyticUtil.checkGeomTypeOf(list.get(0).toString(), GeomTypeEnum.MULTIPOLYGON));
            }
            if("".equals(list.get(1))|| list.get(1)==null){
                throw new ShpFieldException("区带编号"+list.get(4).toString()+"的地震带名称不能为空");
            }else{
                obj.setBeltName(ShpAnalyticUtil.getStringVal(list.get(1).toString(), "地震带名称", true));
            }
            if("".equals(list.get(2))|| list.get(2)==null){
                throw new ShpFieldException("区带编号"+list.get(4).toString()+"的震级上限不能为空");
            }else{
                obj.setMagnitudeLimit(BigDecimal.valueOf(ShpAnalyticUtil.getDoubleVal(list.get(2).toString(), "震级上限", true)));
            }
            if("".equals(list.get(3))|| list.get(3)==null){
                throw new ShpFieldException("区带编号"+list.get(4).toString()+"的本底震级不能为空");
            }else{
                obj.setBackgroundMagnitude(BigDecimal.valueOf(ShpAnalyticUtil.getDoubleVal(list.get(3).toString(), "本底震级", true)));
            }
            if("".equals(list.get(4))|| list.get(4)==null){
                throw new ShpFieldException("区带编号不能为空");
            }else{
                obj.setZoneNumber(ShpAnalyticUtil.getStringVal(list.get(4).toString(), "区带编号", true));
            }
            if("".equals(list.get(5))|| list.get(5)==null){
                throw new ShpFieldException("区带编号"+list.get(4).toString()+"的地震带内容不能为空");
            }else{
                obj.setBeltContent(ShpAnalyticUtil.getStringVal(list.get(5).toString(), "地震带内容", true));
            }
            obj.setCreateUser(PlatformSessionContext.getUserID());
            obj.setCreateTime(new Date());
            obj.setDelFlag(YNEnum.N.toString());
            obj.setBeltId(UUIDGenerator.getUUID());
            arrayList.add(obj);
        }
        return arrayList;
    }

    public RestResponse getBeltYwData(QueryByVersionParam queryByVersionParam) {
        List<SeismotectionBelt> list = seismotectionRepository.getBeltYwData(queryByVersionParam);
        if (queryByVersionParam.getPage() != null && queryByVersionParam.getRows() != null) {
            Long total = seismotectionRepository.countByBeltDataVersion(queryByVersionParam);
            return RestResponse.succeed(new HashMap<String, Object>() {{
                put("data", list);
                put("total", total);
                put("title",  getBeltFieldTable());
                put("page", queryByVersionParam.getPage());
                put("rows", queryByVersionParam.getRows());
                put("totalPage", PageUtil.totalPage(total, queryByVersionParam.getRows()));
            }});
        } else {
            return RestResponse.succeed(new HashMap<String, Object>() {{
                put("data", list);
                put("title",  getBeltFieldTable());
            }});
        }
    }
    public List<TableVo> getBeltFieldTable(){
        Field[] declaredFields = SeismotectionBelt.class.getDeclaredFields();
        List<TableVo> list = new ArrayList<>();
        if(declaredFields.length>0){
            for(Field field : declaredFields){
                FieldDesc fieldDesc = new FieldDesc();
                field.setAccessible(true);
                EntityValue entityValue = field.getAnnotation(EntityValue.class);
                if(entityValue==null){
                    continue;
                }
                TableVo vo = new TableVo();
                vo.setLabel(entityValue.name());
                vo.setProp(field.getName());
                list.add(vo);
            }
        }
        return list;
    }

    public List<FieldDesc>  getBeltFieldDesc() {
        Field[] declaredFields = SeismotectionBelt.class.getDeclaredFields();
        List<FieldDesc> list = new ArrayList<>();
        AtomicInteger sno = new AtomicInteger(1);
        if(declaredFields.length>0){
            for(Field field : declaredFields){
                FieldDesc fieldDesc = new FieldDesc();
                field.setAccessible(true);
                EntityValue entityValue = field.getAnnotation(EntityValue.class);
                if(entityValue==null){
                    continue;
                }
                String type = entityValue.type();
                String must = entityValue.must();
                String name = entityValue.name();
                String desc = entityValue.desc();
                fieldDesc.setType(type).setMust(must).setName(name).setDesc(desc).setSno(sno.get());
                sno.getAndAdd(1);
                list.add(fieldDesc);
            }
        }
        return list;
    }


    public void updateBeltLs(String versionCode, String tempVersionCode) {
        seismotectionRepository.updateBeltLs(versionCode,tempVersionCode);
    }

    public void updateZoneLs(String versionCode, String tempVersionCode) {
        seismotectionRepository.updateZoneLs(versionCode,tempVersionCode);
    }

    public void deleteZoneByVersion(String versionCode) {
        seismotectionRepository.deleteZoneByVersion(versionCode);
    }

    public RestResponse getZoneYwData(QueryByVersionParam queryByVersionParam) {
        List<SeismotectionZone> list = seismotectionRepository.getZoneYwData(queryByVersionParam);
        if (queryByVersionParam.getPage() != null && queryByVersionParam.getRows() != null) {
            Long total = seismotectionRepository.countByZoneDataVersion(queryByVersionParam);
            return RestResponse.succeed(new HashMap<String, Object>() {{
                put("data", list);
                put("total", total);
                put("title",  getZoneFieldTable());
                put("page", queryByVersionParam.getPage());
                put("rows", queryByVersionParam.getRows());
                put("totalPage", PageUtil.totalPage(total, queryByVersionParam.getRows()));
            }});
        } else {
            return RestResponse.succeed(new HashMap<String, Object>() {{
                put("data", list);
                put("title",  getZoneFieldTable());
            }});
        }
    }

    public List<TableVo> getZoneFieldTable(){
        Field[] declaredFields = SeismotectionZone.class.getDeclaredFields();
        List<TableVo> list = new ArrayList<>();
        if(declaredFields.length>0){
            for(Field field : declaredFields){
                FieldDesc fieldDesc = new FieldDesc();
                field.setAccessible(true);
                EntityValue entityValue = field.getAnnotation(EntityValue.class);
                if(entityValue==null){
                    continue;
                }
                TableVo vo = new TableVo();
                vo.setLabel(entityValue.name());
                vo.setProp(field.getName());
                list.add(vo);
            }
        }
        return list;
    }
    public List<FieldDesc>  getZoneFieldDesc() {
        Field[] declaredFields = SeismotectionZone.class.getDeclaredFields();
        List<FieldDesc> list = new ArrayList<>();
        AtomicInteger sno = new AtomicInteger(1);
        if(declaredFields.length>0){
            for(Field field : declaredFields){
                FieldDesc fieldDesc = new FieldDesc();
                field.setAccessible(true);
                EntityValue entityValue = field.getAnnotation(EntityValue.class);
                if(entityValue==null){
                    continue;
                }
                String type = entityValue.type();
                String must = entityValue.must();
                String name = entityValue.name();
                String desc = entityValue.desc();
                fieldDesc.setType(type).setMust(must).setName(name).setDesc(desc).setSno(sno.get());
                sno.getAndAdd(1);
                list.add(fieldDesc);
            }
        }
        return list;
    }

    public Integer getBeltValidDataNum(String versionCode) {
        return seismotectionRepository.getBeltValidDataNum(versionCode);
    }
    public Integer getZoneValidDataNum(String versionCode) {
        return seismotectionRepository.getZoneValidDataNum(versionCode);
    }

    public SeismotectionBelt getYwBeltDetails(String id) {
        return seismotectionRepository.getYwBeltDetails(id);
    }

    public SeismotectionZone getYwZoneDetails(String id) {
        return seismotectionRepository.getYwZoneDetails(id);
    }
}
